package com.siecom.module;

import android.os.SystemClock;
import android.util.Log;

import com.siecom.hostservice.HKBaseApplication;
import com.siecom.nativelibs.SerialPort;
import com.siecom.tool.ByteTool;
import com.siecom.tool.CrashHandler;
import com.siecom.tool.Timer;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * Created by zhq on 2016/6/23.
 */
public class SerialPortModule {

    public final static String TAG = "SerialPortModule";
    protected SerialPort serialPort;
    private InputStream mInputStream;
    private OutputStream mOutputStream;
    protected volatile boolean stopRun = false;

    public void setStopRun(boolean stopRun) {
        this.stopRun = stopRun;
    }

    public boolean isStopRun() {
        return stopRun;
    }

    public boolean initSerialPort(String serialDev, int baudRate) {

        try {
            serialPort = new SerialPort(new File(serialDev), baudRate, 0);
            mInputStream = serialPort.getInputStream();
            mOutputStream = serialPort.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
            // CrashHandler.saveCrashInfo2File(e);
            return false;
        }
        return true;
    }

    protected int read(byte recvBuf[], int recvLen, long waitTime)
            throws IOException {
        long lBeginTime = System.currentTimeMillis();// 更新当前秒计数
        long lCurrentTime = 0;
        int nRet = 0;
        int nReadedSize = 0;
        synchronized (this) {
            while (true) {

                if (mInputStream.available() > 0) {
                    nRet = mInputStream.read(recvBuf, nReadedSize,
                            (recvLen - nReadedSize));
                    if (nRet > 0) {
                        nReadedSize += nRet;
                        if (recvLen == nReadedSize)
                            return 0;
                    }
                }
                lCurrentTime = System.currentTimeMillis();
                if ((lCurrentTime - lBeginTime) > waitTime) {
                    return 2;
                }

            }
        }
    }

    public synchronized void flush() {
        try {
            mOutputStream.flush();
            while (mInputStream.available() > 0) {
                mInputStream.read();

            }
        } catch (IOException e) {
            e.printStackTrace();
            HKBaseApplication.saveCatchInfo2File(e);
        }
    }

    protected synchronized void write(byte[] data) {
        try {
            mOutputStream.write(data);
        } catch (IOException e) {
            e.printStackTrace();
            HKBaseApplication.saveCatchInfo2File(e);
        }
    }

    public void writeFlush(byte[] reqMsg, int reqMsgLen) {
        try {
            synchronized (this) {
                while (mInputStream.available() > 0) {
                    mInputStream.read();
                }
                mOutputStream.write(reqMsg, 0, reqMsgLen);
            }
        } catch (IOException e) {
            e.printStackTrace();
            HKBaseApplication.saveCatchInfo2File(e);
        }
    }

    public void closeSerialPort() {

        try {
            synchronized (this) {
                if (mInputStream != null)
                    mInputStream.close();
                if (mOutputStream != null)
                    mOutputStream.close();
                if (serialPort != null)
                    serialPort.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public synchronized int RecvBytes(byte[] rspMsg, int index, int wantedLen, int timeOutMs) {
        byte[] tempBuf = new byte[wantedLen];
        int ret = 0;
        try {
            ret = receiveBytes(tempBuf, wantedLen, timeOutMs);

        } catch (IOException e) {
            e.printStackTrace();
            return -1;
        }
        if (ret < 0) {
            return ret;
        }
        try {
            System.arraycopy(tempBuf, 0, rspMsg, index, ret);
        }catch (ArrayIndexOutOfBoundsException e){
            e.printStackTrace();
            return -2;
        }

        return ret;
    }

    public synchronized int receiveBytes(byte[] rspMsg, int wantedLen, int timeOutMs) throws IOException {
        int reveiveLen = 0;
        int availabelLen = 0;
        int readLenPerTime = 0;
        Timer tm = null;
        if (rspMsg == null) {

            return -1;
        }

        if (timeOutMs > 0) {
            tm = new Timer(timeOutMs);
            tm.start();

        }
        while (wantedLen > 0) {
            if (timeOutMs > 0) {
                if (tm.timeOut()) {
                    Log.e(TAG, "tm.timeOut!!");
                    break;
                }
            }
            availabelLen = mInputStream.available();

            if (availabelLen > 0) {

                readLenPerTime = mInputStream.read(rspMsg, reveiveLen, wantedLen);

                // Log.e("recv_source:", ByteTool.bytearrayToHexString(rspMsg,readLenPerTime));

                wantedLen -= readLenPerTime;
                reveiveLen += readLenPerTime;
            }
            SystemClock.sleep(5);
        }
        return reveiveLen;
    }

    public void Quick32Crc(byte[] bData, int length, byte[] crcOut) {

        if (serialPort != null) {
            serialPort.QuickCrc32(bData, length, crcOut);
        }
    }

}
